package com.example.demo;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Lists;
import feign.Feign;
import feign.Logger;
import feign.Retryer;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
import org.springframework.cloud.openfeign.FeignFormatterRegistrar;
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
import org.springframework.cloud.openfeign.support.SpringDecoder;
import org.springframework.cloud.openfeign.support.SpringEncoder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;


/**
 * @author cthanatos
 * @title: FeignClientConfig
 * @projectName fenqibao
 * @description: TODO
 * @date 2020/1/1915:02
 */
@Configuration
@ConditionalOnClass(Feign.class)
public class FeignClientConfig implements FeignFormatterRegistrar {
    @Bean
    @ConditionalOnMissingBean
    public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
        ObjectMapper objectMapper = builder.createXmlMapper(false).build();
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        return objectMapper;
    }

    @Bean
    @ConditionalOnMissingBean
    public Decoder feignDecoder(ObjectMapper objectMapper) {
        HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
        ObjectFactory<HttpMessageConverters> objectFactory = () -> new HttpMessageConverters(jacksonConverter);
        return new ResponseEntityDecoder(new SpringDecoder(objectFactory));
//        return new ResponseEntityDecoder(new BugfixSpringDecoder(objectFactory));
    }


    @Bean
    @ConditionalOnMissingBean
    public Encoder feignEncoder(ObjectMapper objectMapper, ObjectFactory<HttpMessageConverters> messageConverters) {
        final List<HttpMessageConverter<?>> converters = messageConverters.getObject().getConverters();
        objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
        HttpMessageConverter jacksonConverter = new MappingJackson2HttpMessageConverter(objectMapper);
        ObjectFactory<HttpMessageConverters> messageConvertersObjectFactory = new ObjectFactory<HttpMessageConverters>() {
            @Override
            public HttpMessageConverters getObject() throws BeansException {
                List<HttpMessageConverter<?>> list = Lists.newArrayList();
                list.addAll(converters);
                MapFormHttpMessageConverter mapFormHttpMessageConverter = new MapFormHttpMessageConverter();
                list.add(mapFormHttpMessageConverter);
                list.add(jacksonConverter);
                HttpMessageConverters newconverters = new HttpMessageConverters(list);
                return newconverters;
            }
        };
        return new SpringEncoder(messageConvertersObjectFactory);
    }

    @Override
    public void registerFormatters(FormatterRegistry formatterRegistry) {
        formatterRegistry.addConverter(Date.class, String.class, new Converter<Date, String>() {
            @Override
            public String convert(Date date) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                return sdf.format(date);
            }
        });
        formatterRegistry.addConverter(String.class, Date.class, new Converter<String, Date>() {
            @Override
            public Date convert(String s) {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                try {
                    return sdf.parse(s);
                } catch (ParseException e) {
                    e.printStackTrace();
                }
                return null;
            }
        });
    }

    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }

    /**
     * 默认关闭feign的重试功能，feign默认会进行五次重试
     */
    @Bean
    public Retryer feignRetryer() {
        return Retryer.NEVER_RETRY;
    }
}